/**
 * $RCSfile: ,v $
 * $Revision: $
 * $Date: $
 * 
 * Copyright (C) 2004-2010 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package org.jivesoftware.spark.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.regex.Pattern;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jivesoftware.MainWindow;
import org.jivesoftware.Spark;
import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromContainsFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.component.tabbedPane.SparkTab;
import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPane;
import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPaneListener;
import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
import org.jivesoftware.spark.ui.rooms.GroupChatRoom;
import org.jivesoftware.spark.util.SwingTimerTask;
import org.jivesoftware.spark.util.TaskEngine;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.alerts.SparkToaster;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;

import cn.newgrand.netcall.muc.MUCUtil;

/**
 * Contains all <code>ChatRoom</code> objects within Spark.
 * 消息的监听工作由各个具体的房间进行操作。房间中收到后消息触发messageListener的messageReceive
 * 容器不对服务器发过来的消息做监听。
 *
 * @author Derek DeMoro
 */
public class ChatContainer extends SparkTabbedPane implements MessageListener, ChangeListener, KeyListener {
	private static final long serialVersionUID = 3725711237490056136L;

	/**
     * List of all ChatRoom Listeners.
     */
    private final List<ChatRoomListener> chatRoomListeners = new ArrayList<ChatRoomListener>();

    private final List<ChatRoom> chatRoomList = new ArrayList<ChatRoom>();

    private final Map<String, PacketListener> presenceMap = new HashMap<String, PacketListener>();

    private static final String WELCOME_TITLE = SparkRes.getString(SparkRes.WELCOME);

    private ChatFrame chatFrame;
    
    private LocalPreferences localPref;

    private final TimerTask focusTask;

    /**
     * Creates the ChatRooms to hold all ChatRooms.
     */
    public ChatContainer() {
        // Assign location
        super(SettingsManager.getLocalPreferences().isTabTopPosition() ? JTabbedPane.TOP : JTabbedPane.BOTTOM);

        // Set minimum size
        setMinimumSize(new Dimension(450, 350));
        // Don't allow tabs to shrink and allow scrolling.

        enableDragAndDrop();
        
        addSparkTabbedPaneListener(new SparkTabbedPaneListener() {
            public void tabRemoved(SparkTab tab, Component component, int index) {
                stateChanged(null);
                if (component instanceof ChatRoom) {
                    closeChatRoom((ChatRoom)component);
//                    if(!getChatRooms().contains((ChatRoom)component)){
//                    	removeTabAt(index);
//                    }
                }
                else if (component instanceof ContainerComponent) {
                    ((ContainerComponent)component).closing();
                }
            }

            public void tabAdded(SparkTab tab, Component component, int index) {
                stateChanged(null);
            }

            public void tabSelected(SparkTab tab, Component component, int index) {
                stateChanged(null);
                // Notify ChatRoomListeners that the tab has been activated.
                if (component instanceof ChatRoom) {
                    fireChatRoomActivated((ChatRoom)component);
                    //TODO 和上面一段代码替换一下位置以后，切换chatroom保持聊天输入窗不再有效
                    ((ChatRoom)component).resizePreferSizeToLast();
                }
            }

            public void allTabsRemoved() {
                chatFrame.setTitle("");
                chatFrame.setVisible(false);
//                chatFrame.setState(Frame.NORMAL);
//                chatFrame.dispose();
            }


            public boolean canTabClose(SparkTab tab, Component component) {
                return true;
            }
        });

        setCloseButtonEnabled(true);

        // Add Key Navigation
        addKeyNavigation();

        this.setFocusable(false);

        setOpaque(true);

        setBackground(Color.white);

        // Create task for focusing chat.
        focusTask = new SwingTimerTask() {
            public void doRun() {
                try {
                    //chatFrame.requestFocus();
                    ChatRoom chatRoom = getActiveChatRoom();
                    chatRoom.requestFocusInWindow();
                    chatRoom.getChatInputEditor().requestFocusInWindow();
                }
                catch (ChatRoomNotFoundException e1) {
                    // Ignore. There may legitamtly not be a chat room.
                }
            }
        };

    }


    /**
     * Adds navigation capability to chat rooms. Users can navigate using the alt-left or right arrow keys.
     */
    private void addKeyNavigation() {
        KeyStroke leftStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
        String leftStrokeString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(leftStroke);

        // Handle Left Arrow
        this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("alt " + leftStrokeString + ""), "navigateLeft");
        this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("alt " + leftStrokeString + ""), "navigateLeft");
        this.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("alt " + leftStrokeString + ""), "navigateLeft");
        this.getActionMap().put("navigateLeft", new AbstractAction("navigateLeft") {
			private static final long serialVersionUID = -8677467560602512074L;

			public void actionPerformed(ActionEvent evt) {
                navigateLeft();
            }
        });

        KeyStroke rightStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
        String rightStrokeString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(rightStroke);

        // Handle Right Arrow
        this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("alt " + rightStrokeString + ""), "navigateRight");
        this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("alt " + rightStrokeString + ""), "navigateRight");
        this.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("alt " + rightStrokeString + ""), "navigateRight");


        this.getActionMap().put("navigateRight", new AbstractAction("navigateRight") {
			private static final long serialVersionUID = -7676330627598261416L;

			public void actionPerformed(ActionEvent evt) {
                navigateRight();
            }
        });

        this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("ESCAPE"), "escape");
        this.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ESCAPE"), "escape");

        this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("Ctrl W"), "escape");
        this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "escape");

        this.getActionMap().put("escape", new AbstractAction("escape") {
			private static final long serialVersionUID = 5165074248488666495L;

			public void actionPerformed(ActionEvent evt) {
                closeActiveRoom();
            }
        });

        this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK), "shiftCmdW");
        this.getActionMap().put("shiftCmdW", new AbstractAction("shiftCmdW") {
			private static final long serialVersionUID = -1179625099164632251L;

			public void actionPerformed(ActionEvent evt) {
                closeAllChatRooms();
            }
        });

        // Add KeyMappings
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "searchContacts");
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("control F"), "searchContacts");
        getActionMap().put("searchContacts", new AbstractAction("searchContacts") {
			private static final long serialVersionUID = -6904085783599775675L;

			public void actionPerformed(ActionEvent evt) {
                SparkManager.getUserManager().searchContacts("", SparkManager.getChatManager().getChatContainer().getChatFrame());
            }
        });
    }

    /**
     * 添加一个chatroom到容器中。增加presenceFilter,添加presence到容器， ChatRoom UI,添加到chatRoomList中，fireChatRoomOpened事件
     * 需要注意的是：
     * 在添加chinaGroupRoom的时候，双击打开、消息过来时房间加入到容器中，
     * 关闭的时候不操作 chatroom中的具体内容，就只是将chatcontainer中该chatroom tab页关闭掉
     *
     * @param room the ChatRoom to add.
     */
    public synchronized void addChatRoom(final ChatRoom room) {
        createFrameIfNeeded();
        

        //因为加进来的room已经包含了全部的信息，所以 当添加的是chinaGroupChatRoom的时候，
        //仅作如下几项工作，包括对房间本身以及对容器：
        // 增加presenceFilter,添加presence到容器，
        //不做如下工作:再添加一个messageListener到room中
        //modified by sidney  
        boolean isAddedChinaGroupRoom = false;
        if(room instanceof GroupChatRoom){
        	if(MUCUtil.isChinaGroupChat(((GroupChatRoom) room).getMultiUserChat().getRoom())){
        		isAddedChinaGroupRoom = true;
        	}
        }
        
        room.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 0, Color.LIGHT_GRAY));
        AndFilter presenceFilter = new AndFilter(new PacketTypeFilter(Presence.class), new FromContainsFilter(room.getRoomname()));

        // Next, create a packet listener. We use an anonymous inner class for brevity.
        PacketListener myListener = new PacketListener() {
            public void processPacket(final Packet packet) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        handleRoomPresence((Presence)packet);
                    }
                });
            }
        };


        SparkManager.getConnection().addPacketListener(myListener, presenceFilter);

        // Add to PresenceMap
        presenceMap.put(room.getRoomname(), myListener);

        String tooltip;
        if (room instanceof ChatRoomImpl) {
            tooltip = ((ChatRoomImpl)room).getParticipantJID();
            String nickname = SparkManager.getUserManager().getUserNicknameFromJID(((ChatRoomImpl)room).getParticipantJID());

            tooltip = "<html><body><b>Contact:&nbsp;</b>" + nickname + "<br><b>JID:&nbsp;</b>" + tooltip;
        }
        else {
            tooltip = room.getRoomname();
        }

        // Create ChatRoom UI and dock
        SparkTab tab = addTab(room.getTabTitle(), room.getTabIcon(), room, tooltip);
//        System.out.println("chatContainer"+room.getTabTitle());
        tab.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent e) {
                checkTabPopup(e);
            }

            public void mousePressed(MouseEvent e) {
                checkTabPopup(e);
            }
        });
        
        //如果是添加一个chinaGroup群聊，那就不再添加room的message监听，因为关闭的时候没有删除过
        //modified by sidney
        
        if(isAddedChinaGroupRoom){
        	if(!room.containsMessageListerner(this))
        		room.addMessageListener(this);
        }else{
        	room.addMessageListener(this);
        }
        
        // Remove brand panel
        final String title = getTabAt(0).getActualText();
        if (title.equals(WELCOME_TITLE)) {
            chatFrame.setTitle(room.getRoomTitle());
        }
        

        final TimerTask visibleTask = new SwingTimerTask() {
            public void doRun() {
                checkVisibility(room);
            }
        };

        TaskEngine.getInstance().schedule(visibleTask, 100);
        
//		SwingUtilities.invokeLater(new Runnable() {
//			@Override
//			public void run() {
//				// TODO Auto-generated method stub
//				checkVisibility(room);
//			}
//		});
        
//        if(!chatFrame.isVisible()) chatFrame.setVisible(true);
        
        // Add to ChatRoomList
        chatRoomList.add(room);

        // Notify users that the chat room has been opened.
        fireChatRoomOpened(room);

        // Focus Chat
        focusChat();
        
//        System.out.println(chatFrame.isVisible());
        
        // Add Room listeners to override issue with input maps and keybinding on the mac.
        if (Spark.isMac()) {
            room.getChatInputEditor().addKeyListener(this);
        }
    }

    public void addContainerComponent(ContainerComponent comp) {
        createFrameIfNeeded();

        addTab(comp.getTabTitle(), comp.getTabIcon(), comp.getGUI(), comp.getToolTipDescription());
        chatFrame.setTitle(comp.getFrameTitle());
        checkVisibility(comp.getGUI());

        if (getSelectedComponent() != comp) {
            // Notify Decorators
            SparkManager.getChatManager().notifySparkTabHandlers(comp.getGUI());
        }
    }

    /**
     * Handles the presence of a one to one chat room.
     *
     * @param p the presence to handle.
     */
    private void handleRoomPresence(final Presence p) {
        final String roomname = StringUtils.parseBareAddress(p.getFrom());
        ChatRoom chatRoom;
        try {
            chatRoom = getChatRoom(roomname);
        }
        catch (ChatRoomNotFoundException e1) {
            Log.debug("Could not locate chat room " + roomname);
            return;
        }

        final String userid = StringUtils.parseResource(p.getFrom());
        if (p.getType() == Presence.Type.unavailable) {
            fireUserHasLeft(chatRoom, userid);
        }
        else if (p.getType() == Presence.Type.available) {
            fireUserHasJoined(chatRoom, userid);
        }

        // Change tab icon
        if (chatRoom instanceof ChatRoomImpl) {
            // Notify state change.
            int tabLoc = indexOfComponent(chatRoom);
            if (tabLoc != -1) {
                SparkManager.getChatManager().notifySparkTabHandlers(chatRoom);
            }
        }
    }

    private void checkVisibility(Component component) {
//    	System.out.println((new Date()).getTime());
//    	System.out.println("chatFrame No "+"\t"+"state"+"\t"+"isVisible\t"+"isInfocus"+"\t"+"window is focus");
//    	System.out.println("0\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        if (!chatFrame.isVisible() && SparkManager.getMainWindow().isFocusOwner()) {
//        	System.out.println("1\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        	chatFrame.setState(Frame.NORMAL);
            chatFrame.setVisible(true);
            //TODO
//            System.out.println("here is problem");
        }
        else if (chatFrame.isVisible() && !chatFrame.isInFocus()) {
//        else if (chatFrame.isVisible() && !chatFrame.isInFocus()&&chatFrame.getState() == Frame.ICONIFIED) {
        	
//        	System.out.println("2\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        	startFlashing(component, false, null, null);
        }
        else if (chatFrame.isVisible() && chatFrame.getState() == Frame.ICONIFIED) {
//        	System.out.println("3\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        	
        	// Set to new tab.
            int tabLocation = indexOfComponent(component);
            setSelectedIndex(tabLocation);

            // If the ContactList is in the tray, we need better notification by flashing
            // the chatframe.
            startFlashing(component, false, null, null);
            
        }

        // Handle when chat frame is visible but the Contact List is not.
        else if (chatFrame.isVisible() && !SparkManager.getMainWindow().isVisible()) {
//        	System.out.println("4\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        	startFlashing(component, false, null, null);
            
        }
        else if (!chatFrame.isVisible()) {
//        	System.out.println("5\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        	// Set to new tab.
            int tabLocation = indexOfComponent(component);
            setSelectedIndex(tabLocation);

            if (Spark.isWindows()) {
                chatFrame.setFocusableWindowState(false);
                chatFrame.setState(Frame.ICONIFIED);
            }
         	chatFrame.setFocusableWindowState(true);
            chatFrame.setVisible(true);

            
            // If the ContactList is in the tray, we need better notification by flashing
            // the chatframe.
            if (!SparkManager.getMainWindow().isVisible()) {
                startFlashing(component, false, null, null);
            }
            else if (chatFrame.getState() == Frame.ICONIFIED) {
                startFlashing(component, false, null, null);
            }

            if (component instanceof ChatRoom) {
                chatFrame.setTitle(((ChatRoom)component).getRoomTitle());
                startFlashing(component, false,null,null);
            }
        }
    }

 
    
    private void handleMessageNotification(final ChatRoom chatRoom, boolean customMsg, String customMsgText, String customMsgTitle) {
        ChatRoom activeChatRoom = null;        
        
        try {
            activeChatRoom = getActiveChatRoom();
        }
        catch (ChatRoomNotFoundException e1) {
            Log.error(e1);
        }
                
        if (chatFrame.isVisible() && (chatFrame.getState() == Frame.ICONIFIED || chatFrame.getInactiveTime() > 20000)) {
            int tabLocation = indexOfComponent(chatRoom);
            setSelectedIndex(tabLocation);
            groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
//            System.out.println("6\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
            return;
        }

        if (!chatFrame.isVisible() && SparkManager.getMainWindow().isFocusOwner()) {
            chatFrame.setState(Frame.NORMAL);
            chatFrame.setVisible(true);
//            System.out.println("7\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        }
        else if (chatFrame.isVisible() && !chatFrame.isInFocus()) {
            groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
//            System.out.println("8\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        }
        else if (chatFrame.isVisible() && chatFrame.getState() == Frame.ICONIFIED) {
//        	System.out.println("9\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
        	
        	// Set to new tab.
            int tabLocation = indexOfComponent(chatRoom);
            setSelectedIndex(tabLocation);

            // If the ContactList is in the tray, we need better notification by flashing
            // the chatframe.
            groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
        }

        // Handle when chat frame is visible but the Contact List is not.
        else if (chatFrame.isVisible() && !SparkManager.getMainWindow().isVisible() && !chatFrame.isInFocus()) {
//        	System.out.println("10\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
            groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
        }
        else if (!chatFrame.isVisible()) {
//        	System.out.println("11\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
            // Set to new tab.
            int tabLocation = indexOfComponent(chatRoom);
            setSelectedIndex(tabLocation);
    
            if (Spark.isWindows()) {
            	chatFrame.setFocusableWindowState(false);
            	chatFrame.setExtendedState(Frame.ICONIFIED);
            }
            chatFrame.setFocusableWindowState(true);
            chatFrame.setVisible(true);

            
            // If the ContactList is in the tray, we need better notification by flashing
            // the chatframe.
            if (!SparkManager.getMainWindow().isVisible()) {
                groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
            }
            else if (chatFrame.getState() == Frame.ICONIFIED) {
                groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
            }

            chatFrame.setTitle(chatRoom.getRoomTitle());
        }
        else if (chatRoom != activeChatRoom) {
            groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
        }
    }
    
    /**
     * 该方法在简单的关闭群房间的时候用
     * 这里要区别于removeChinaGroupRoom方法
     * @param room
     */
    public void closeChinaGroupRoom(ChatRoom room){
    	final PacketListener listener = presenceMap.get(room.getRoomname());
//    	if (listener != null) {
//    		SparkManager.getConnection().removePacketListener(listener);
//    	}
    	presenceMap.remove(room.getRoomname());
    	chatRoomList.remove(room);
    	//participant 中的监听
    	
    	//容器接收到消息，触发room写历史消息界面，所以这个不能删除
//    	room.removeMessageListener(this);
    	
    	// Remove mappings
    	
    	chatRoomList.remove(room);
    	
    	room.getChatInputEditor().removeKeyListener(this);
    	
    	// 消息记录不能清掉
//    	room.getTranscriptWindow().cleanup();
    	closeTab(room);
//    	fireChatRoomClosed(room);
    }
    /**
     * 与closechinaGroupRoom不同，
     * 区别在于removeChinaGroupRoom在群被销毁或提出群的时候用
     * @param chatRoom
     */
    public void removeChinaGroupRoom(ChatRoom chatRoom){
    	//TODO
    	ChatRoom room;
    	if(null==chatRoom){
	        try {
	            room = getActiveChatRoom();
	        }
	        catch (ChatRoomNotFoundException e1) {
	            Component comp = getActiveRoom();
	            if (comp != null) {
	                boolean canClose = ((ContainerComponent)comp).closing();
	                if (canClose) {
	                    closeTab(comp);
	                }
	            }
	
	            return;
	        }
    	}else{
    		room =chatRoom;
    	}
    	if(room!=null){
	        // Confirm end session
	       	leaveChatRoom(room);
	        room.closeChatRoom();
	        cleanupChatRoom(room);
	        
	//        cleanupActivedRoom(room);
    	}
        if(getTabCount()==0){
        	if(chatFrame!=null){
        	chatFrame.setTitle("");
        	chatFrame.setVisible(false);
        	}
//        	chatFrame.setState(Frame.NORMAL);
//        	chatFrame.dispose();
        }
    }

    /**
     * 关闭指定的窗口，参数为空时关闭当前的聊天窗口
     * 
     * 如果为chatroom 
     * @param chatRoom 
     */
    public void closeChatRoom(ChatRoom chatRoom) {
    	//TODO
    	ChatRoom room;
    	if(null==chatRoom){
	        try {
	            room = getActiveChatRoom();
	        }
	        catch (ChatRoomNotFoundException e1) {
	            Component comp = getActiveRoom();
	            if (comp != null) {
	                boolean canClose = ((ContainerComponent)comp).closing();
	                if (canClose) {
	                    closeTab(comp);
	                }
	            }
	
	            return;
	        }
    	}else{
    		room =chatRoom;
    	}

        // Confirm end session
        boolean isGroupChat = room.getChatType() == Message.Type.groupchat;
        boolean isChinaGroup = false;
        if(room instanceof GroupChatRoom){
        	isChinaGroup = ((GroupChatRoom) room).getConferenceService().endsWith(MUCUtil.getChinaGroupServiceName());
        }
        if (isGroupChat) {
        	//modified by sidney 如果是chinaGroup则不错操作
			if (!isChinaGroup) {
				final int ok = JOptionPane.showConfirmDialog(
						chatFrame,Res.getString("message.end.conversation",
								room.getTabTitle()),
						Res.getString("title.confirmation"),
						JOptionPane.YES_NO_OPTION);
				if (ok == JOptionPane.OK_OPTION) {

					leaveChatRoom(room);
					room.closeChatRoom();
					cleanupChatRoom(room);
				}
			}else{
				closeChinaGroupRoom(room);
	    		//TODO 怎么处理群关闭的问题
//				room.setVisible(false);
			}
        }
        else {
        	leaveChatRoom(room);
            room.closeChatRoom();
            cleanupChatRoom(room);
        }
        
//        cleanupActivedRoom(room);
        
        if(getTabCount()==0){
        	chatFrame.setTitle("");
        	chatFrame.setVisible(false);
//        	chatFrame.setState(Frame.NORMAL);
//        	chatFrame.dispose();
        }
    }
    
    /**
     * 关闭当前聊天窗口
     */
    public void closeActiveRoom(){
    	closeChatRoom(null);
    }
    
    public void closeGroupRoomNoAsk(ChatRoom chatRoom){
    	//TODO
    	ChatRoom room;
    	if(null==chatRoom){
	        try {
	            room = getActiveChatRoom();
	        }
	        catch (ChatRoomNotFoundException e1) {
	            Component comp = getActiveRoom();
	            if (comp != null) {
	                boolean canClose = ((ContainerComponent)comp).closing();
	                if (canClose) {
	                    closeTab(comp);
	                }
	            }
	
	            return;
	        }
    	}else{
    		room =chatRoom;
    	}

        // Confirm end session
        boolean isGroupChat = room.getChatType() == Message.Type.groupchat;
        if (isGroupChat) {
               	leaveChatRoom(room);
                room.closeChatRoom();
                cleanupChatRoom(room);
            }
        else {
        	leaveChatRoom(room);
            room.closeChatRoom();
            cleanupChatRoom(room);
        }
        
//        cleanupActivedRoom(room);
        
        if(getTabCount()==0){
        	chatFrame.setTitle("");
        	chatFrame.setVisible(false);
//        	chatFrame.setState(Frame.NORMAL);
//        	chatFrame.dispose();
        }
    }
    
    /**
     * 清除chat容器中chatroom的资源
     * 
     * Removes the ChatRoom resources.
     *
     * @param room the room to remove.
     */
    private void cleanupChatRoom(ChatRoom room) {
//    	if (room.isActive()) {
////            room.leaveChatRoom();
//    		//TODO
////            room.closeChatRoom();
//    		closeActiveRoom(room);
//    	}
    	
    	final PacketListener listener = presenceMap.get(room.getRoomname());
    	if (listener != null) {
    		SparkManager.getConnection().removePacketListener(listener);
    	}
    	
    	fireChatRoomClosed(room);
    	room.removeMessageListener(this);
    	
    	// Remove mappings
    	presenceMap.remove(room.getRoomname());
    	
    	chatRoomList.remove(room);
    	
    	room.getChatInputEditor().removeKeyListener(this);
    	
    	// Clear all Text :)
    	room.getTranscriptWindow().cleanup();
    }
    
    /**
     * 如果容器中还有群聊没有关闭，则保留该群聊
     * Close all chat rooms.
     * 
     */
    public void closeAllChatRooms() {
        LocalPreferences pref = SettingsManager.getLocalPreferences();

        if (MainWindow.getInstance().isDocked() || !pref.isAutoCloseChatRoomsEnabled()) {
            return;
        }

        for (ChatRoom chatRoom : new ArrayList<ChatRoom>(chatRoomList)) {
//            closeTab(chatRoom);
//            closeActiveRoom();
//            chatRoom.closeChatRoom();
        	closeChatRoom(chatRoom);
        }

        for (int i = 0; i < getTabCount(); i++) {
            Component comp = getComponentAt(i);
            if (comp instanceof ContainerComponent) {
                ((ContainerComponent)comp).closing();
            }
            if(comp instanceof GroupChatRoom){
            	break;
            	}

            closeTab(comp);
        }
    }

    /**
     * Leaves a ChatRoom. Leaving a chat room does everything but close the room itself.
     * 离开房间，删除chat容器对presence的监听
     * @param room the room to leave.
     */
    public void leaveChatRoom(ChatRoom room) {
        // Notify that the chatroom has been left.
        fireChatRoomLeft(room);
        room.leaveChatRoom();

        final PacketListener listener = presenceMap.get(room.getRoomname());
        if (listener != null && SparkManager.getConnection().isConnected()) {
            SparkManager.getConnection().removePacketListener(listener);
        }
    }

    /**
     * Returns a ChatRoom by name.
     *
     * @param roomName the name of the ChatRoom.
     * @return the ChatRoom
     * @throws ChatRoomNotFoundException if the room was not found.
     */
    public ChatRoom getChatRoom(String roomName) throws ChatRoomNotFoundException {
        for (int i = 0; i < getTabCount(); i++) {
            ChatRoom room = null;
            try {
                room = getChatRoom(i);
            }
            catch (ChatRoomNotFoundException e1) {
                // Ignore
            }

            if (room != null && room.getRoomname().equalsIgnoreCase(roomName) && room.isActive()) {
                return room;
            }
        }
        throw new ChatRoomNotFoundException(roomName + " not found.");
    }

    /**
     * Returns a ChatRoom in the specified tab location.
     *
     * @param location the tab location.
     * @return the ChatRoom found.
     * @throws ChatRoomNotFoundException thrown if the room is not found.
     */
    public ChatRoom getChatRoom(int location) throws ChatRoomNotFoundException {
        if (getTabCount() < location) {
        	throw new ChatRoomNotFoundException();
        }
        try {
            Component comp = getComponentAt(location);
            if (comp instanceof ChatRoom) {
                return (ChatRoom)comp;
            }
        }
        catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
            Log.error("Error getting Chat Room", outOfBoundsEx);
        }

        throw new ChatRoomNotFoundException();
    }

    /**
     * Returns the Active ChatRoom.
     *
     * @return the ChatRoom active in the tabbed pane.
     * @throws ChatRoomNotFoundException is thrown if no chat room is found.
     */
    public ChatRoom getActiveChatRoom() throws ChatRoomNotFoundException {
        int location = getSelectedIndex();
        if (location != -1) {
            return getChatRoom(location);
        }
        throw new ChatRoomNotFoundException();
    }

    /**
     * Returns the Active Component.
     *
     * @return the Component active in the tabbed pane.
     */
    public Component getActiveRoom() {
        int location = getSelectedIndex();
        if (location != -1) {
            return getComponentAt(location);
        }

        return null;
    }

    /**
     * Activates the specified ChatRoom.
     *
     * @param room the ChatRoom to activate.
     */
    public void activateChatRoom(ChatRoom room) {
        int tabLocation = indexOfComponent(room);
        setSelectedIndex(tabLocation);

        chatFrame.bringFrameIntoFocus();
        focusChat();
    }

    /**
     * Activates the component in tabbed pane.
     *
     * @param component the component contained within the tab to activate.
     */
    public void activateComponent(Component component) {
        int tabLocation = indexOfComponent(component);
        if (tabLocation != -1) {
            setSelectedIndex(tabLocation);
        }

        chatFrame.bringFrameIntoFocus();
        focusChat();
    }

    /**
     * Used for Tray Notifications.
     *
     * @param room    the ChatRoom where the message was received.
     * @param message the message received.
     */
    public void messageReceived(ChatRoom room, Message message) {
        room.increaseUnreadMessageCount();
        SparkManager.getWorkspace().getTranscriptPlugin().persistChatRoom(room);
        fireNotifyOnMessage(room, false, null, null);
    }
    
    /**
     * Used for Tray Notifications.
     *
     * @param chatRoom the ChatRoom where the message was received.
     * @param customMsg
     * @param customMsgText
     * @param customMsgTitle
     */    
    public void fireNotifyOnMessage(final ChatRoom chatRoom, final boolean customMsg, final String customMsgText, final String customMsgTitle) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                handleMessageNotification(chatRoom, customMsg, customMsgText, customMsgTitle);
            }
        });
    }

    /***
     *
     * @param room
     * @param message
     */
    public void messageSent(ChatRoom room, Message message) {
        fireChatRoomStateUpdated(room);
    }

    /**
     * Notification that the tab pane has been modified. Generally by changing of the tabs.
     *
     * @param e the ChangeEvent.
     */
    public void stateChanged(ChangeEvent e) {
        // Stop the flashing only if the chat frame is in focus.
        if (chatFrame.isInFocus()) {
            stopFlashing();
        }

        final Object o = getSelectedComponent();
        if (o instanceof ChatRoom) {
            final ChatRoom room = (ChatRoom)o;
            focusChat();

            // Set the title of the room.
            chatFrame.setTitle(room.getRoomTitle());
            chatFrame.setIconImage(SparkManager.getMainWindow().getIconImage());
        }
        else if (o instanceof ContainerComponent) {
            final ContainerComponent comp = (ContainerComponent)o;
            chatFrame.setTitle(comp.getFrameTitle());
            chatFrame.setIconImage(comp.getTabIcon().getImage());

            SparkManager.getChatManager().notifySparkTabHandlers(comp.getGUI());
        }
    }


    private void stopFlashing() {
        try {
            // Get current tab
//        	System.out.println("stop flashing" );
            int selectedIndex = getSelectedIndex();
            if (selectedIndex != -1) {
                Component comp = getComponentAt(selectedIndex);
                if (comp != null) {
                    stopFlashing(comp);
                }
            }
        }
        catch (Exception e) {
            Log.error(e);
        }
    }


    /**
     * 
     * 清除chatRoom顶部的tab标签
     * 并不是清除房间内容
     * 这里标签面板和内容面板是分开的
     * 
     * Closes a tab of a room.
     *
     * @param component the component inside of the tab to close.
     */
    public void closeTab(Component component) {
        int location = indexOfComponent(component);
        if (location == -1) {
            return;
        }

        if (getTabCount() == 0) {
            chatFrame.setTitle("");
        }

        this.removeTabAt(location);
    }

    public String toString() {
        StringBuffer buf = new StringBuffer();
        for (ChatRoom room : chatRoomList) {
            buf.append("Roomname=").append(room.getRoomname()).append("\n");
        }
        return buf.toString();
    }


    /**
     * Returns true if there are any Rooms present.
     *
     * @return true if Rooms are present, otherwise false.
     */
    public boolean hasRooms() {
        int count = getSelectedIndex();
        return count != -1;
    }

    /**
     * Adds a ChatRoom listener to ChatRooms. The
     * listener will be called when either a ChatRoom has been
     * added, removed, or activated.
     *
     * @param listener the <code>ChatRoomListener</code> to register
     */
    public void addChatRoomListener(ChatRoomListener listener) {
        if (!chatRoomListeners.contains(listener)) {
            chatRoomListeners.add(listener);
        }
    }

    /**
     * Removes the specified <code>ChatRoomListener</code>.
     *
     * @param listener the <code>ChatRoomListener</code> to remove
     */
    public void removeChatRoomListener(ChatRoomListener listener) {
        chatRoomListeners.remove(listener);
    }

    /**
     * Notifies users that a <code>ChatRoom</code> has been opened.
     *
     * @param room - the <code>ChatRoom</code> that has been opened.
     */
    public void fireChatRoomOpened(ChatRoom room) {
    	//检查chatroom是不是已经打开过
    	if(!room.isFireOpened()){
	        for (ChatRoomListener chatRoomListener : new ArrayList<ChatRoomListener>(chatRoomListeners)) {
	            chatRoomListener.chatRoomOpened(room);
	        }
	        room.setFireOpened(true);
    	}
    }

    /**
     * Notifies users that a <code>ChatRoom</code> has been left.
     *
     * @param room - the <code>ChatRoom</code> that has been left
     */
    protected void fireChatRoomLeft(ChatRoom room) {
        for (ChatRoomListener chatRoomListener : new HashSet<ChatRoomListener>(chatRoomListeners)) {
            chatRoomListener.chatRoomLeft(room);
        }
    }

    /**
     * Notifies users that a <code>ChatRoom</code> has been closed.
     *
     * @param room - the <code>ChatRoom</code> that has been closed.
     */
    protected void fireChatRoomClosed(ChatRoom room) {
        for (ChatRoomListener chatRoomListener : new HashSet<ChatRoomListener>(chatRoomListeners)) {
            chatRoomListener.chatRoomClosed(room);
        }
    }

    /**
     * Notifies users that a <code>ChatRoom</code> has been activated.
     *
     * @param room - the <code>ChatRoom</code> that has been activated.
     */
    protected void fireChatRoomActivated(ChatRoom room) {
        for (ChatRoomListener chatRoomListener : new HashSet<ChatRoomListener>(chatRoomListeners)) {
            chatRoomListener.chatRoomActivated(room);
        }
    }

    /**
     * Notifies users that a user has joined a <code>ChatRoom</code>.
     *
     * @param room   - the <code>ChatRoom</code> that a user has joined.
     * @param userid - the userid of the person.
     */
    protected void fireUserHasJoined(final ChatRoom room, final String userid) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                for (ChatRoomListener chatRoomListener : new HashSet<ChatRoomListener>(chatRoomListeners)) {
                    chatRoomListener.userHasJoined(room, userid);
                }
            }
        });

    }

    /**
     * Notifies users that a user has left a <code>ChatRoom</code>.
     *
     * @param room   - the <code>ChatRoom</code> that a user has left.
     * @param userid - the userid of the person.
     */
    protected void fireUserHasLeft(final ChatRoom room, final String userid) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                for (ChatRoomListener chatRoomListener : new HashSet<ChatRoomListener>(chatRoomListeners)) {
                    chatRoomListener.userHasLeft(room, userid);
                }
            }
        });

    }

    /**
     * Starts flashing of MainWindow.
     *
     * @param comp the Component to check if a message has been inserted
     *             but the room is not the selected room.
     */
    public void startFlashing(final Component comp, final boolean customMsg, final String customMsgText, final String customMsgTitle) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
//                	System.out.println("the state of chatFrame before flash is "+chatFrame.isVisible());
                    final int index = indexOfComponent(comp);
                    if (index != -1) {
                        // Check notifications.
                        if (SettingsManager.getLocalPreferences().isChatRoomNotificationsOn() || !(comp instanceof GroupChatRoom)) {
                            if (comp instanceof ChatRoom) {
                        	if(comp instanceof GroupChatRoom) {
//                        		System.out.println(comp);
                        		if(null!=((GroupChatRoom) comp).getLastMessage())
                        	    if(!((GroupChatRoom) comp).isBlocked(((GroupChatRoom) comp).getLastMessage().getFrom())) 
                        		checkNotificationPreferences((ChatRoom)comp, customMsg, customMsgText, customMsgTitle); 
                        	} else {
//                        		System.out.println("chat room");
                        	    checkNotificationPreferences((ChatRoom)comp, customMsg, customMsgText, customMsgTitle);
                        	}
                            }
                        }

                        // Notify decorators
                        SparkManager.getChatManager().notifySparkTabHandlers(comp);
                    }

                    boolean flashAllowed = SettingsManager.getLocalPreferences().isChatRoomNotificationsOn() || !(comp instanceof GroupChatRoom);

                    if (!chatFrame.isInFocus() && flashAllowed) {
//                    	System.out.println("s\t"+chatFrame.getState()+"\t"+chatFrame.isVisible()+"\t"+chatFrame.isInFocus()+"\t"+SparkManager.getMainWindow().isFocusOwner());
                        SparkManager.getNativeManager().flashWindow(chatFrame);
                    }
                }
                catch (Exception ex) {
                    Log.error("Issue in ChatRooms with tab location.", ex);
                }
            }
        });
    }


    public void fireChatRoomStateUpdated(final ChatRoom room) {
        final int index = indexOfComponent(room);
        if (index != -1) {
            SparkManager.getChatManager().notifySparkTabHandlers(room);
        }
    }

    /**
     * Checks to see if the <code>ChatFrame</code> should stop flashing.
     *
     * @param component the component that should be notified.
     */
    public void stopFlashing(final Component component) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    // Stop the flashing
                    SparkManager.getNativeManager().stopFlashing(chatFrame);

                    // Notify decorators
                    SparkManager.getChatManager().notifySparkTabHandlers(component);
                }
                catch (Exception ex) {
                    Log.error("Could not stop flashing because " + ex.getMessage(), ex);
                }


            }
        });
    }

    /**
     * Handles Notification preferences for incoming messages and rooms.
     *
     * @param room the chat room.
     * @param fileTransfer if it is a file transfer then true
     * @param fileTName the file name being transfered (if fileTransfer applies)
     *
     */
    private void checkNotificationPreferences(final ChatRoom room, boolean customMsg, String customMsgText, String customMsgTitle) {
        LocalPreferences pref = SettingsManager.getLocalPreferences();

        if (pref.getWindowTakesFocus()) {
            chatFrame.setState(Frame.NORMAL);
            chatFrame.setVisible(true);
        }

        if (pref.getShowToasterPopup()) {
            SparkToaster toaster = new SparkToaster();
            toaster.setCustomAction(new AbstractAction() {
				private static final long serialVersionUID = -2759404307378067515L;

				public void actionPerformed(ActionEvent actionEvent) {
                    chatFrame.setState(Frame.NORMAL);
                    chatFrame.setVisible(true);
                    int tabLocation = indexOfComponent(room);
                    if (tabLocation != -1) {
                        setSelectedIndex(tabLocation);
                    }
                }
            });

            toaster.setDisplayTime(5000);
            toaster.setBorder(BorderFactory.createBevelBorder(0));
            
            String nickname = room.getRoomTitle();
            toaster.setToasterHeight(150);
            toaster.setToasterWidth(200);


            int size = room.getTranscripts().size();
            if(customMsg) {
                toaster.setTitle(customMsgTitle);
                toaster.showToaster(room.getTabIcon(), customMsgText);
            } else {
                toaster.setTitle(nickname);
                if (size > 0) {
                    Message message = room.getTranscripts().get(size - 1);

                    toaster.showToaster(room.getTabIcon(), message.getBody());
                }
            }
        }
//        System.out.println(chatFrame.isVisible());
    }

     /**
     * Performs several group chat checks
     *
     * chatRoom the chat room that needs to be passed
     * customMsg whether or not this is a custom message
     * customMsgText if any custom message should appear in the popup
     * customMsgTitle whether or not the toaster should have any popup
     *
     **/
    private void groupChatMessageCheck(ChatRoom chatRoom, boolean customMsg, String customMsgText, String customMsgTitle) {
        // predefine if this is a group chat message or not
        localPref = SettingsManager.getLocalPreferences();
        boolean isGroupChat = chatRoom.getChatType() == Message.Type.groupchat;
        int size = chatRoom.getTranscripts().size();
        
        // is this a group chat message and is my name in it?
        if (isGroupChat) {
            // is a group chat, perform some functions
        	if(size==0)return;
            Message lastChatMessage = chatRoom.getTranscripts().get(size - 1);
            String mucNickNameT = lastChatMessage.getFrom();
            String[] mucNickName = mucNickNameT.split("/");
            String finalRoomName = chatRoom.getRoomTitle();
            
            if (localPref.isMucHighToastEnabled()) {
                // allowed to check for new messages containing name
                String myNickName = chatRoom.getNickname();
                String myUserName = SparkManager.getSessionManager().getUsername();
                Pattern usernameMatch = Pattern.compile(myUserName, Pattern.CASE_INSENSITIVE);
                Pattern nicknameMatch = Pattern.compile(myNickName, Pattern.CASE_INSENSITIVE);
                
                if (usernameMatch.matcher(lastChatMessage.getBody()).find() || nicknameMatch.matcher(lastChatMessage.getBody()).find()) {
                    // match, send new message
                    boolean customMsgS = true;
                    String customMsgTextS = Res.getString("group.chat.name.match") + " " + finalRoomName + " by " + mucNickName[1] + " (" + lastChatMessage.getBody() + ")";
                    String customMsgTitleS = Res.getString("group.chat.name.notification");
                       
                    startFlashing(chatRoom, customMsgS, customMsgTextS, customMsgTitleS);
                    return;
                } else {
                    // regular group message
                    boolean customMsgS = true;
                    String customMsgTextS = mucNickName[1] + " says: " + lastChatMessage.getBody();
                    String customMsgTitleS = finalRoomName;
                    
                    startFlashing(chatRoom, customMsgS, customMsgTextS, customMsgTitleS);
                    return;
                }
            } else {
                // regular group message
                boolean customMsgS = true;
                String customMsgTextS = mucNickName[1] + " says: " + lastChatMessage.getBody();
                String customMsgTitleS = finalRoomName;
                
                startFlashing(chatRoom, customMsgS, customMsgTextS, customMsgTitleS);
                return;
            }
        } else if (customMsg) {
            // probablt a file transfer request
            boolean customMsgS = customMsg;
            String customMsgTextS = customMsgText;
            String customMsgTitleS = customMsgTitle;
            
            startFlashing(chatRoom, customMsgS, customMsgTextS, customMsgTitleS);
            return;
        } else {
            // normal personal chat
//        	if(size==0) return;
        	boolean customMsgS = true;
            String customMsgTextS = null ;
            String customMsgTitleS = null;
        	
        	try{
        		Message lastChatMessage = chatRoom.getTranscripts().get(size - 1);
        		String finalRoomName = chatRoom.getRoomTitle();
        		customMsgTextS = lastChatMessage.getBody();
            	customMsgTitleS = finalRoomName;
        	}catch(Exception ex){
        		Log.error("there is error when send invitaion "+ex.getMessage());
        	}
        	
            startFlashing(chatRoom, customMsgS, customMsgTextS, customMsgTitleS);
            return;
        }
    }
    
    public void setChatRoomTitle(ChatRoom room, String title) {
        int index = indexOfComponent(room);
        if (index != -1) {
            SparkTab tab = getTabAt(index);
            fireChatRoomStateUpdated(room);
            tab.setTabTitle(room.getTabTitle());
        }
    }

    private void createFrameIfNeeded() {
        if (chatFrame != null) {
            return;
        }
        LocalPreferences pref = SettingsManager.getLocalPreferences();

        if (pref.isDockingEnabled()) {
            chatFrame = MainWindow.getInstance();
        }
        else {
            chatFrame = new ChatFrame();
        }

        chatFrame.addWindowListener(new WindowAdapter() {
            public void windowActivated(WindowEvent windowEvent) {
                stopFlashing();
                int sel = getSelectedIndex();
                if (sel == -1) {
                    return;
                }
                final ChatRoom room;
                try {
                    room = getChatRoom(sel);
                    focusChat();

                    // Set the title of the room.
                    chatFrame.setTitle(room.getRoomTitle());
                }
                catch (ChatRoomNotFoundException e1) {
                    // Nothing to do
                }

            }

            public void windowDeactivated(WindowEvent windowEvent) {
            }


            public void windowClosing(WindowEvent windowEvent) {
            	if(getTabCount() > 1){
            		if(JOptionPane.showConfirmDialog(chatFrame, "是否确认关闭已打开的"+getTabCount()+"个聊天窗口", "关闭窗口", JOptionPane.YES_NO_OPTION) != 0){
                		return;
                	}
            	}
                // Save layout
                chatFrame.saveLayout();
                SparkManager.getChatManager().getChatContainer().closeAllChatRooms();
                chatFrame.setVisible(false);
//                chatFrame.setState(Frame.NORMAL);
//                chatFrame.dispose();
            }
        });

        // Start timer
        handleStaleChats();
    }


    /**
     * Brings the chat into focus.
     */
    public void focusChat() {


        TaskEngine.getInstance().schedule(focusTask, 50);
    }

    public Collection<ChatRoom> getChatRooms() {
        return new ArrayList<ChatRoom>(chatRoomList);
    }

    public ChatFrame getChatFrame() {
        return chatFrame;
    }

    public void blinkFrameIfNecessary(final JFrame frame) {

        final MainWindow mainWindow = SparkManager.getMainWindow();

        if (mainWindow.isFocusOwner()) {
            frame.setVisible(true);
        }
        else {
            // Set to new tab.
            if (Spark.isWindows()) {
                frame.setState(Frame.ICONIFIED);
                SparkManager.getNativeManager().flashWindow(frame);

                frame.setVisible(true);
                frame.addWindowListener(new WindowAdapter() {
                    public void windowActivated(WindowEvent e) {
                        SparkManager.getNativeManager().stopFlashing(frame);
                    }
                });
            }
        }
    }


    private void checkTabPopup(MouseEvent e) {
        final SparkTab tab = (SparkTab)e.getSource();
        if (!e.isPopupTrigger()) {
            return;
        }

        final JPopupMenu popup = new JPopupMenu();

        // Handle closing this room.
        Action closeThisAction = new AbstractAction() {
			private static final long serialVersionUID = 5002889397735856123L;

			public void actionPerformed(ActionEvent e) {
                ChatRoom chatRoom = (ChatRoom)getComponentInTab(tab);
                if (chatRoom != null) {
                    closeTab(chatRoom);
                }
            }
        };
        closeThisAction.putValue(Action.NAME, Res.getString("message.close.this.chat"));
        popup.add(closeThisAction);


        if (getChatRooms().size() > 1) {
            // Handle closing other rooms.
            Action closeOthersAction = new AbstractAction() {
				private static final long serialVersionUID = 1869236917427431585L;

				public void actionPerformed(ActionEvent e) {
                    ChatRoom chatRoom = (ChatRoom)getComponentInTab(tab);
                    if (chatRoom != null) {
                        for (ChatRoom cRoom : getChatRooms()) {
                            if (chatRoom != cRoom) {
                                closeTab(cRoom);
                            }
                        }
                    }
                }
            };

            closeOthersAction.putValue(Action.NAME, Res.getString("message.close.other.chats"));
            popup.add(closeOthersAction);

            Action closeOldAction = new AbstractAction() {
				private static final long serialVersionUID = 1L;

				public void actionPerformed(ActionEvent e) {
                    for (ChatRoom rooms : getStaleChatRooms()) {
                        closeTab(rooms);
                    }
                }
            };
            closeOldAction.putValue(Action.NAME, Res.getString("message.close.stale.chats"));
            popup.add(closeOldAction);

        }


        popup.show(tab, e.getX(), e.getY());

    }

    /**
     * Returns a Collection of stale chat rooms.
     *
     * @return a collection of stale chat rooms.
     */
    public Collection<ChatRoom> getStaleChatRooms() {
        final List<ChatRoom> staleRooms = new ArrayList<ChatRoom>();
        for (ChatRoom chatRoom : getChatRooms()) {
            long lastActivity = chatRoom.getLastActivity();
            long currentTime = System.currentTimeMillis();

            long diff = currentTime - lastActivity;
            int minutes = (int)(diff / (60 * 1000F));

            LocalPreferences pref = SettingsManager.getLocalPreferences();
            int timeoutMinutes = pref.getChatLengthDefaultTimeout();

            int unreadCount = chatRoom.getUnreadMessageCount();

            if (timeoutMinutes <= minutes && unreadCount == 0) {
                staleRooms.add(chatRoom);
            }
        }

        return staleRooms;
    }

    /**
     * Checks every room every 30 seconds to see if it's timed out.
     */
    private void handleStaleChats() {
        int delay = 1000;   // delay for 1 second.
        int period = 60000;  // repeat every minute.

        final TimerTask task = new SwingTimerTask() {
            public void doRun() {
                for (ChatRoom chatRoom : getStaleChatRooms()) {
                    // Notify decorators
                    SparkManager.getChatManager().notifySparkTabHandlers(chatRoom);
                }
            }
        };


        TaskEngine.getInstance().scheduleAtFixedRate(task, delay, period);
    }

    private void navigateRight() {
        int selectedIndex = getSelectedIndex();
        if (selectedIndex > -1) {
            int count = getTabCount();
            if (selectedIndex == (count - 1)) {
                setSelectedIndex(0);
            }
            else {
                setSelectedIndex(selectedIndex + 1);
            }
        }
    }

    private void navigateLeft() {
        int selectedIndex = getSelectedIndex();
        if (selectedIndex > 0) {
            setSelectedIndex(selectedIndex - 1);
        }
        else {
            setSelectedIndex(getTabCount() - 1);
        }
    }

    // Handle key listener events for mac only :)
    public void keyTyped(KeyEvent keyEvent) {
        // Nothing to do.
    }

    public void keyPressed(KeyEvent keyEvent) {
        if (keyEvent.isMetaDown()) {
            if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
                navigateRight();
            }
            else if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
                navigateLeft();
            }

        }
    }

    public void keyReleased(KeyEvent keyEvent) {
        // Nothing to do.
    }

    /**
     * Returns the total number of unread messages in Spark.
     *
     * @return the total number of unread messages in Spark.
     */
    public int getTotalNumberOfUnreadMessages() {
        int messageCount = 0;
        for (ChatRoom chatRoom : chatRoomList) {
            messageCount += chatRoom.getUnreadMessageCount();
        }

        return messageCount;
    }
}

